﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Caching;

namespace Chowpoo.Cache
{
    public class Cache2
    {

        /*
        //由 CacheItemPriority 枚举表示。缓存在退出对象时使用该值；具有较低成本的对象在具有较高成本的对象之前被从缓存移除。
        //public enum CacheItemPriority
        //{
        // AboveNormal = 4,
        // BelowNormal = 2,
        // Default = 3,
        // High = 5,
        // Low = 1,
        // Normal = 3,
        // NotRemovable = 6
        //}
        * 如果 Cache 中已保存了具有相同 key 参数的项，则对此方法的调用将失败。若要使用相同的 key 参数覆盖现有的 Cache 项，请使用 Insert 方法。

        无法同时设置 absoluteExpiration 和 slidingExpiration 参数。如果要让缓存项在特定时间到期，可将 absoluteExpiration 参数设置为特定时间，并将 slidingExpiration 参数设置为 NoSlidingExpiration。

        如果要让缓存项在最后一次访问该项后的某段时间之后到期，可将 slidingExpiration 参数设置为到期间隔，并将 absoluteExpiration 参数设置为 NoAbsoluteExpiration。
        //add和Insert的差别是
        //public void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration)
        //{
        // DateTime utcAbsoluteExpiration = DateTimeUtil.ConvertToUniversalTime(absoluteExpiration);
        // this._cacheInternal.DoInsert(true, key, value, dependencies, utcAbsoluteExpiration, slidingExpiration, CacheItemPriority.Normal, null, true);
        //}

        //public object Add(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback)
        //{
        // DateTime utcAbsoluteExpiration = DateTimeUtil.ConvertToUniversalTime(absoluteExpiration);
        // return this._cacheInternal.DoInsert(true, key, value, dependencies, utcAbsoluteExpiration, slidingExpiration, priority, onRemoveCallback, false);
        //}
        */


        /// <summary>
        ///缓存对象
        /// </summary>
        protected static System.Web.Caching.Cache WebCache = HttpRuntime.Cache;//( volatile)编译器就老老实实的每次都从内存中读取这个变量值,不是在CPU的缓存里读

        /// <summary>
        /// 获取数据缓存
        /// </summary>
        /// <param name="cacheKey">键</param>
        public static object GetCache(string cacheKey)
        {
            if (string.IsNullOrEmpty(cacheKey))
                return null;
            return WebCache.Get(cacheKey);
        }


        /********************************************时间偏差的缓存*****************************************************************/
        /*
        *
        * 使用时间偏差内的缓存的意思是在缓存创建后slidingExpiration时间偏差内连续访问缓存项的话继续保持指定缓存项对象
         * 用 偏差 过期的缓存absoluteExpiration参数要设置NoAbsoluteExpiration，NoAbsoluteExpiration是DateTime.MaxValue的意思
        * 就要slidingExpiration时间偏差内连续访问的话连续缓存，如果在slidingExpiration时间偏差内没人用缓存项拿删除
        * static Cache()
        {
        NoAbsoluteExpiration = DateTime.MaxValue;
        NoSlidingExpiration = TimeSpan.Zero;
        s_sentinelRemovedCallback = new CacheItemRemovedCallback(SentinelEntry.OnCacheItemRemovedCallback);
        }
        */
        /// <summary>
        /// 在指定的slidingExpiration时间偏差内连续访问缓存项的话(级别Normal = 3），继续保持指定缓存项对象里加入对象
        /// 别的级别（NotRemovable = 6，High = 5,AboveNormal = 4,Normal = 3,BelowNormal = 2,Low = 1）
        /// absoluteExpiration=NoAbsoluteExpiration，slidingExpiration=TimeSpan.FromSeconds(expire)
        /// </summary>
        /// <param name="cacheKey">对象的键值</param>
        /// <param name="o">缓存的对象</param>
        /// <param name="expire">时间偏差</param>
        public static void InsertNormalSlidingCache(string cacheKey, object o, int expire)
        {
            if (string.IsNullOrEmpty(cacheKey) || o == null)
            {
                return;
            }
            WebCache.Insert(cacheKey, o, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromSeconds(expire), CacheItemPriority.Normal, null);
        }
        /// <summary>
        /// 在指定的slidingExpiration时间偏差内连续访问缓存项的话(高级别High = 5），继续保持指定缓存项对象里加入对象
        /// 别的级别（NotRemovable = 6，High = 5,AboveNormal = 4,Normal = 3,BelowNormal = 2,Low = 1）
        /// absoluteExpiration=NoAbsoluteExpiration，slidingExpiration=TimeSpan.FromSeconds(expire)
        /// </summary>
        /// <param name="cacheKey">对象的键值</param>
        /// <param name="o">缓存的对象</param>
        /// <param name="expire">时间偏差</param>
        public static void InsertHighSlidingCache(string cacheKey, object o, int expire)
        {
            if (string.IsNullOrEmpty(cacheKey) || o == null)
            {
                return;
            }
            WebCache.Insert(cacheKey, o, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromSeconds(expire), CacheItemPriority.High, null);
        }
        /// <summary>
        /// 在指定的absoluteExpiration时间偏差内连续访问缓存项的话，继续保持指定缓存项对象里加入对象
        /// absoluteExpiration=NoAbsoluteExpiration，absoluteExpiration=TimeSpan.FromSeconds(expire)
        /// </summary>
        /// <param name="cacheKey">对象的键值</param>
        /// <param name="o">缓存的对象</param>
        /// <param name="expire">时间偏差</param>
        /// <param name="jibie">缓存级别，级别高到低存放内存数据（NotRemovable = 6，High = 5,AboveNormal = 4,Normal = 3,BelowNormal = 2,Low = 1）</param>
        public static void InsertSlidingCache(string cacheKey, object o, int expire, int jibie)
        {
            if (string.IsNullOrEmpty(cacheKey) || o == null)
            {
                return;
            }
            CacheItemPriority dareje;
            switch (jibie)
            {
                case 1: dareje = CacheItemPriority.Low; break;
                case 2: dareje = CacheItemPriority.BelowNormal; break;
                case 3: dareje = CacheItemPriority.Normal; break;
                case 4: dareje = CacheItemPriority.AboveNormal; break;
                case 5: dareje = CacheItemPriority.High; break;
                case 6: dareje = CacheItemPriority.NotRemovable; break;
                default: dareje = CacheItemPriority.Normal; break;
            }
            WebCache.Insert(cacheKey, o, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromSeconds(expire), dareje, null);
        }
        /********************************************绝对过期的缓存*****************************************************************/
        /*
        *
        * 使用绝对过期的缓存的意思是在缓存创建后过了absoluteExpiration时间后缓存过期
        * 用绝对过期的缓存slidingExpiration参数要设置TimeSpan.Zero，TimeSpan.Zero是0的意思
        * 也就是说没时间偏差
        * static Cache()
        {
        NoAbsoluteExpiration = DateTime.MaxValue;
        NoSlidingExpiration = TimeSpan.Zero;
        s_sentinelRemovedCallback = new CacheItemRemovedCallback(SentinelEntry.OnCacheItemRemovedCallback);
        }
        */


        /// <summary>
        /// 使用绝对过期的缓存中加入当前对象（过了expire时间后缓存过期)
        /// </summary>
        /// <param name="cacheKey">对象的键值</param>
        /// <param name="o">缓存的对象</param>
        /// <param name="expire">到期时间,单位:秒(0时最大的时间，高的级别，表示永不过期）</param>
        /// <param name="jibie">缓存级别（NotRemovable = 6，High = 5,AboveNormal = 4,Normal = 3,BelowNormal = 2,Low = 1）</param>
        public virtual void InsertAbsoluteCache(string cacheKey, object o, int expire, int jibie)
        {
            if (string.IsNullOrEmpty(cacheKey) || o == null)
            {
                return;
            }
            CacheItemPriority dareje;
            switch (jibie)
            {
                case 1: dareje = CacheItemPriority.Low; break;
                case 2: dareje = CacheItemPriority.BelowNormal; break;
                case 3: dareje = CacheItemPriority.Normal; break;
                case 4: dareje = CacheItemPriority.AboveNormal; break;
                case 5: dareje = CacheItemPriority.High; break;
                case 6: dareje = CacheItemPriority.NotRemovable; break;
                default: dareje = CacheItemPriority.Normal; break;
            }
            WebCache.Insert(cacheKey, o, null, DateTime.Now.AddSeconds(expire), System.Web.Caching.Cache.NoSlidingExpiration, dareje, null);
        }
        /// <summary>
        /// 使用绝对过期的缓存中加入当前对象(级别是Normal）（过了expire时间后缓存过期)
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="o"></param>
        /// <param name="expire"></param>
        public virtual void InsertAbsoluteNormalCache(string cacheKey, object o, int expire)
        {
            if (string.IsNullOrEmpty(cacheKey) || o == null)
            {
                return;
            }
            WebCache.Insert(cacheKey, o, null, DateTime.Now.AddSeconds(expire), System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
        }

        ///<summary>
        /// 使用绝对过期的缓存中加入当前对象（过了expire时间后过期缓存，absoluteExpiration=DateTime.Now.AddSeconds(expire)）
        /// (slidingExpiration 参数设置成 TimeSpan.Zero ，TimeSpan.Zero就是时间差别0的意思TimeSpan.Zero=0）
        /// </summary>
        /// <param name="cacheKey">对象的键值</param>
        /// <param name="o">缓存的对象</param>
        /// <param name="expire">到期时间,单位:秒(0时最大的时间，高的级别，表示永不过期）</param>
        public virtual void InsertAbsoluteHighCache(string cacheKey, object o, int expire)
        {
            if (string.IsNullOrEmpty(cacheKey) || o == null)
            {
                return;
            }
            if (expire == 0)
            {
                WebCache.Insert(cacheKey, o, null, DateTime.MaxValue, TimeSpan.Zero, CacheItemPriority.High, null);
            }
            else
            {
                WebCache.Insert(cacheKey, o, null, DateTime.Now.AddSeconds(expire), System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.High, null);
            }
        }

        /// <summary>
        /// 清空的有缓存数据
        /// </summary>
        public static void DeleteAllItems()
        {
            IDictionaryEnumerator cacheEnum = HttpRuntime.Cache.GetEnumerator();
            while (cacheEnum.MoveNext())
            {
                WebCache.Remove(cacheEnum.Key.ToString());
            }
        }
        /// <summary>
        /// 清空指定字符开头的所有缓存（不分大小写开头）
        /// </summary>
        /// <param name="prefix">指定字符开头</param>
        public static void DeletePrefixItems(string prefix)
        {
            prefix = prefix.ToLower();
            var itemsRemove = new List<string>();
            IDictionaryEnumerator cacheEnum = HttpRuntime.Cache.GetEnumerator();
            while (cacheEnum.MoveNext())
            {
                if (cacheEnum.Key.ToString().ToLower().StartsWith(prefix))
                {
                    itemsRemove.Add(cacheEnum.Key.ToString());
                }
            }
            foreach (string i in itemsRemove)
            {
                WebCache.Remove(i);
            }
        }
    }
}

